package thieft;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;


public class Juego {
	
	private int casosJugados;
	private Policia policia;
    private List <Ladron> ladrones;
    private List<Capital> capitalesRutaDeEscape;
    private List<Capital> capitalesSinPistas; 
    HashMap<String, Rasgo> rasgosPosibles;

    public Juego() {
    	
    	this.casosJugados = 0; 
        this.policia = new Policia();
        this.ladrones = new ArrayList<Ladron>();
        this.capitalesRutaDeEscape = new ArrayList<Capital>();
        this.capitalesSinPistas = new ArrayList<Capital>();
        this.crearRasgosPosibles();
    }
    
    private void crearRasgosPosibles() {
    	
    	this.rasgosPosibles = new HashMap<String, Rasgo>();
    	//Crea todos los rasgos posibles (20 rasgos)
    	
    	this.rasgosPosibles.put("Femenino", new Rasgo("Sexo", "Femenino"));         
    	this.rasgosPosibles.put("Masculino", new Rasgo("Sexo", "Masculino"));        
    	this.rasgosPosibles.put("Tenis", new Rasgo("Hobby", "Tenis"));         
    	this.rasgosPosibles.put("Musica", new Rasgo("Hobby", "Musica"));          
    	this.rasgosPosibles.put("Alpinismo", new Rasgo("Hobby", "Alpinismo"));       
    	this.rasgosPosibles.put("Paracaidismo", new Rasgo("Hobby", "Paracaidismo")); 
    	this.rasgosPosibles.put("Natacion", new Rasgo("Hobby", "Natacion"));        
    	this.rasgosPosibles.put("Croquet", new Rasgo("Hobby", "Croquet"));         
    	this.rasgosPosibles.put("Castanio", new Rasgo("Cabello", "Castanio")); 
    	this.rasgosPosibles.put("Rubio", new Rasgo("Cabello", "Rubio"));        
    	this.rasgosPosibles.put("Rojo", new Rasgo("Cabello", "Rojo"));        
    	this.rasgosPosibles.put("Negro", new Rasgo("Cabello", "Negro"));        
    	this.rasgosPosibles.put("Anillo", new Rasgo("Senia", "Anillo"));         
    	this.rasgosPosibles.put("Tatuaje", new Rasgo("Senia", "Tatuaje"));        
    	this.rasgosPosibles.put("Cicatriz", new Rasgo("Senia", "Cicatriz"));      
    	this.rasgosPosibles.put("Joyas", new Rasgo("Senia", "Joyas"));           
    	this.rasgosPosibles.put("Descapotable", new Rasgo("Vehiculo", "Descapotable")); 
    	this.rasgosPosibles.put("Limusina", new Rasgo("Vehiculo", "Limusina"));    
    	this.rasgosPosibles.put("Deportivo", new Rasgo("Vehiculo", "Deportivo"));   
    	this.rasgosPosibles.put("Moto", new Rasgo("Vehiculo", "Moto"));        
    }
    
    public String obtenerDiaActual() {
    	
    	return Tiempo.obtenerInstancia().obtenerDia().obtenerNombre();
    }
    
    public int obtenerHoraActual() {
    	
    	return Tiempo.obtenerInstancia().obtenerHoras();
    }
    
    public void modificarNombrePolicia(String nombre) {
    	
    	this.policia.modificarNombre(nombre);
    }
    
    public Policia obtenerPolicia() {
    	
        return this.policia;
    }
    
    public Ladron obtenerLadron() {
    	
    	return this.ladrones.get(0); // Primera posicion para el ladron del caso.
    }
    
    public List<Ladron> obtenerLadrones() {
    	
    	return this.ladrones;
    }
    
    public Rasgo obtenerRasgo(String descripcion) {
    	
    	return this.rasgosPosibles.get(descripcion);
    }

    public int cantidadCasosJugados() {
    	
    	return this.casosJugados;
    }
    
    public void moverPolicia(Capital nuevaCapital) {
    	
        this.policia.viajarACapital(nuevaCapital);
    }
    
    public void comenzarCaso() {
    	          	
    	this.leerArchivoXML();
        
        Tiempo.obtenerInstancia().iniciarTiempo(); 
        
        this.casosJugados = this.casosJugados + 1;
    }
    
    public boolean casoTerminado() {
    	
    	Tiempo tiempo = Tiempo.obtenerInstancia();
    	
    	return ( tiempo.llegoAlLimite() || this.obtenerLadron().estaCapturado() );
    }
    
    public boolean verificarOrdenDeArresto() {
    	
    	Tiempo tiempo = Tiempo.obtenerInstancia();
    	boolean arrestado = false;
    	
        if ( !tiempo.llegoAlLimite() && this.policia.obtenerOrdenDeArresto().ladronConOrdenDeArresto() == this.obtenerLadron() ) {
    		
    		this.policia.aumentarArrestos();
    		arrestado = true;
    	}
    	return arrestado;
    }
    
    public List<Capital> proximasCapitalesAVisitar() {
    	
    	List <Lugar> lugares = this.policia.obtenerCapital().obtenerLugares();
    	  	
       	if ( lugares.get(0).esRutaDeEscape() ) {
       		
       		return this.capitalesAVisitarAleatoriamente(this.capitalesRutaDeEscape, this.capitalesSinPistas);
       			
       	}else {
       		
       		return this.capitalesAVisitarAleatoriamente(this.capitalesSinPistas, this.capitalesRutaDeEscape);
       	} 		
    }
    
    private List<Capital> capitalesAVisitarAleatoriamente(List<Capital> capitalesConMayorProbabilidad, List<Capital> capitalesConMenorProbabilidad) {
    	
    	List<Capital> capitalesAVisitar = new ArrayList<Capital>();
    	Capital capital;
    	
    	for (int i = 0; i < 3 ; i++ ) {
   			
   		    capital = this.obtenerCapitalAleatoria(capitalesAVisitar, capitalesConMayorProbabilidad);
   		    capitalesAVisitar.add(capital);
   		}
   		capital = this.obtenerCapitalAleatoria(capitalesAVisitar, capitalesConMenorProbabilidad);
   		capitalesAVisitar.add(capital);
   		
   		return capitalesAVisitar;
    }
    
    private Capital obtenerCapitalAleatoria(List<Capital> capitalesAVisitar, List<Capital> capitales) {
    	
    	Capital capitalAleatoria;
    	boolean capitalRepetida = true;
    	Random random = new Random();
    	
    	do { 
    		int pos = random.nextInt(capitales.size()); 
    		capitalAleatoria = capitales.get(pos);
    		
    		if ( !capitalesAVisitar.contains(capitalAleatoria) && !capitalAleatoria.equals(this.policia.obtenerCapital())) {
    			
    			capitalRepetida = false;
    		}
    	} while ( capitalRepetida );
    	
    	return capitalAleatoria;
    }
    
    public List<Capital> capitalesRutaDeEscape() {
    	// solo para pasar un test
    	return this.capitalesRutaDeEscape;
    }
    
///////////////////////////////////////////////////////////////////////////////////////
    
    private void leerArchivoXML() {
    	 
    	 //limpia los ladrones
    	 this.ladrones.clear();
    	 
    	 //limpia las capitales
    	 this.capitalesRutaDeEscape.clear();
         this.capitalesSinPistas.clear();
             	 
     //Lee el Archivo XML y crea los objetos 
        		
		//Se crea un SAXBuilder para poder parsear el archivo
	    SAXBuilder builder = new SAXBuilder();
	    File archivoXML = new File( this.policia.obtenerEstado().obtenerArchivoXML() );
	    try {
	    	
	      //Se crea el documento a traves del archivo
            Document document = (Document) builder.build( archivoXML );
          
          //Se obtiene la raiz 'Casos'
            Element raizCasos = document.getRootElement();
            
          //Se obtiene la lista de hijos de la raiz 'Casos'
            List<Element> listaDeCasos = raizCasos.getChildren( "Caso" );
            
          //Se obtiene un solo elemento 'Caso' segun la cantidad de casos jugados (Para No Repetir)
            Element caso = (Element) listaDeCasos.get(this.casosJugados);
            
          //Se obtiene la lista de hijos del tag 'Caso'
            List<Element> hijosCaso = caso.getChildren( "Capitales" );
            
          //Se obtiene el elemento 'Capitales' del tag 'Caso'
            Element capitales = (Element) hijosCaso.get(0);
            
          //Se obtiene la lista de hijos de 'Capitales'
            List<Element> listaDeCapitales = capitales.getChildren( "Capital" );
            
            this.crearObjetoCapital(listaDeCapitales);
            
          
          //Se obtiene la lista de hijos del tag 'Caso'
            hijosCaso = caso.getChildren( "Sospechosos" );
            
          //Se obtiene el elemento 'Sospechosos' del tag 'Caso'
            Element sospechosos = (Element) hijosCaso.get(0);
            
          //Se obtiene la lista de hijos de 'Sospechosos'
            List<Element> listaDeLadrones = sospechosos.getChildren( "Ladron" );
            
          //Se recorre la lista de hijos de 'Sospechosos'
            for ( int i = 0; i < listaDeLadrones.size(); i++ ) {
            	            	
            	//Se obtiene el elemento 'Ladron'
                Element ladron = (Element) listaDeLadrones.get(i);
            
                //Agrega al ladron a la lista de ladrones    
                this.ladrones.add( this.crearObjetoLadron(ladron) );
            }
 
	    }catch ( IOException io ) {
	        System.out.println( io.getMessage() );
	    }catch ( JDOMException jdomex ) {
	        System.out.println( jdomex.getMessage() );
	    }
	}
    
    private void crearObjetoCapital(List<Element> listaDeCapitales) {
    	
    	 //Se recorre la lista de hijos de 'Capitales'
        for ( int i = 0; i < listaDeCapitales.size(); i++ ) {           
      	  
      	  Capital objetoCapital;
      	  Posicion objetoPosicion; 
      	  List<Lugar> listaObjetoLugar = new ArrayList<Lugar>();
      	  
      	//Se obtiene el elemento 'Capital'
            Element capital = (Element) listaDeCapitales.get(i);
            
          //Se obtiene el atributo 'capital' que esta en el tag 'Capital'
            String nombreCapital = capital.getAttributeValue("capital");
            
          //Se obtiene el atributo 'pais' que esta en el tag 'Capital'
            String nombrePais = capital.getAttributeValue("pais");
            
          //Se obtiene la lista de hijos del tag 'Capital'
            List<Element> hijosCapital = capital.getChildren();
            
          //Se obtiene 'Posicion' hijo del tag 'Capital'
            Element posicion = (Element) hijosCapital.get(0);
            String latitud = posicion.getAttributeValue("latitud");
            String longitud = posicion.getAttributeValue("longitud");
          
          // crea el objeto 'Posicion'
            objetoPosicion = new Posicion(Double.parseDouble(latitud), Double.parseDouble(longitud));
                          
          //Se obtiene 'Lugares' hijo del tag 'Capital'
            Element lugares = (Element) hijosCapital.get(1);
            List<Element> listaDeLugares = lugares.getChildren();
     
             //Se recorre la lista de lugares
               for ( int j = 0; j < listaDeLugares.size(); j++ ) {
          	                  	 
          	    //Se obtiene el elemento 'Lugar'
                  Element lugar = (Element) listaDeLugares.get(j);
                  
                //Se obtiene el atributo 'nombre' que esta en el tag 'Lugar'
                  String nombreLugar = lugar.getAttributeValue("nombre");
                  
                //Se obtiene la lista de hijos del tag 'Lugar'
                  List<Element> hijosLugar = lugar.getChildren();
                
                //Se recorre la lista de ConsecuenciaLugar
                  for ( int k = 0; k < hijosLugar.size(); k++ ) { 
                  	
                     //Se obtiene 'ConsecuenciaLugar' hijo del tag 'Lugar'
                       Element consecuenciaLugar = (Element) hijosLugar.get(k);
                  
                       this.crearObjetoConsecuenciaLugar(listaObjetoLugar, consecuenciaLugar, lugar, nombreLugar);
                  }
               }
            
          //Crea el objeto 'Capital' y lo agrega en la lista de Capitales
            objetoCapital = new Capital(nombreCapital, nombrePais, objetoPosicion);
           
            //Agrega Los Lugares a la Capital
            int pos=0;
            while( pos < listaObjetoLugar.size() ) {
          	  
          	  objetoCapital.agregarLugar(listaObjetoLugar.get(pos));
          	
              pos++;
            }
            
            //Agraga la capital a la lista
            if ( listaObjetoLugar.get(0).esRutaDeEscape()) {
         		 this.capitalesRutaDeEscape.add(objetoCapital);
         		 
         		//EL Policia inicia en la primera Capital de Ruta De Escape
                 if ( i == 0 ) { this.policia.capitalInicio(objetoCapital); }
                 
         	  }else {
         		  this.capitalesSinPistas.add(objetoCapital);
         	  }            
        } 
    }
    
    private void crearObjetoConsecuenciaLugar(List<Lugar> listaObjetoLugar, Element consecuenciaLugar, Element lugar, String nombreLugar) {
    	
    	if (consecuenciaLugar.getName() == "Ladron") {
        	
        	ObjetoRobado objetoObjetoRobado;
        	
        	Ladron objetoLadron = this.crearObjetoLadron(consecuenciaLugar);          
            
        	//Se obtiene la lista de hijos del tag 'Ladron'
            List<Element> hijosLadron = consecuenciaLugar.getChildren();
              
            //Se obtiene 'ObjetoRobado' hijo del tag 'Ladron'
              Element objetoRobado = (Element) hijosLadron.get(1);
    
            //Se obtiene el atributo 'objetoRobado' que esta en el tag 'ObjetoRobado'
              String nombreObjetoRobado = objetoRobado.getAttributeValue("objetoRobado");  
        
            //Crea el objeto 'ObjetoRobado'
              objetoObjetoRobado = new ObjetoRobado(nombreObjetoRobado);
        
            //Agrega el 'ObjetoRobado' a 'Ladron' y obtiene su referencia
              objetoLadron.agregarObjetoRobado(objetoObjetoRobado);
            //Agrega al ladron a la lista de ladrones (primera posicion para el ladron del caso). 
              this.ladrones.add(objetoLadron); 
              
            //Crea el objeto 'Lugar' y lo agrega a la lista de objetoLugar
          	listaObjetoLugar.add(new Lugar(nombreLugar, objetoLadron));
              
        }else if (consecuenciaLugar.getName() == "Pista") {
        
        	String pista = consecuenciaLugar.getAttributeValue("pista");
        	
           //Crea el objeto 'Pista'
        	Pista objetoPista = new Pista(pista);
        	
        	//Crea el objeto 'Lugar' y lo agrega a la lista de objetoLugar
        	listaObjetoLugar.add(new Lugar(nombreLugar, objetoPista));
        	
        }else if (consecuenciaLugar.getName() == "Cuchillo") {
        	//Crea el objeto 'Cuchillo'
        	Cuchillo objetoCuchillo = new Cuchillo();
        	
        	//Crea el objeto 'Lugar' y lo agrega a la lista de objetoLugar
        	listaObjetoLugar.add(new Lugar(nombreLugar, objetoCuchillo));
        	
        }else if (consecuenciaLugar.getName() == "ArmaDeFuego") {
        	//Crea el objeto 'Cuchillo'
        	ArmaDeFuego objetoArmaDeFuego = new ArmaDeFuego();
        	
        	//Crea el objeto 'Lugar' y lo agrega a la lista de objetoLugar
        	listaObjetoLugar.add(new Lugar(nombreLugar, objetoArmaDeFuego));
        	
        }else if (consecuenciaLugar.getName() == "Nada") {
        	//Crea el objeto 'Nada'
        	Nada objetoNada = new Nada();
        	
        	//Crea el objeto 'Lugar' y lo agrega a la lista de objetoLugar
        	listaObjetoLugar.add(new Lugar(nombreLugar, objetoNada));
        }
    }
    
    private Ladron crearObjetoLadron(Element ladron) {
        	
    	    List<Rasgo> objetosRasgos = new ArrayList<Rasgo>();
    	
        	String nombreLadron = ladron.getAttributeValue("nombre");
        	
        	//Se crea el objetoLadron 
        	Ladron objetoLadron = new Ladron(nombreLadron);
            
            //Se obtiene la lista de hijos del tag 'Ladron'
              List<Element> hijosLadron = ladron.getChildren();
           
            //Se obtiene 'Rasgos' hijo del tag 'Ladron'
              Element rasgos = (Element) hijosLadron.get(0);
          
            //Se obtiene la lista de hijos del tag 'Rasgos'
              List<Element> listaDeRasgos = rasgos.getChildren("Rasgo");
                    
            //Se recorre la lista de rasgos
              for ( int k = 0; k < listaDeRasgos.size(); k++ ) {
              	                   	  
                //Se obtiene el elemento 'Categoria'
                  Element rasgo = (Element) listaDeRasgos.get(k);
                                          
                //Se obtiene el atributo 'descripcion' que esta en el tag 'Rasgo'
                  String descripcion = rasgo.getAttributeValue("descripcion");
                    
                //obtiene el objeto Rasgo
                  objetosRasgos.add( this.obtenerRasgo(descripcion) );
              }
            //Agrega los rasgos al ladron
              objetoLadron.agregarRasgos(objetosRasgos);
                
            return objetoLadron;
    }
  
////////////////////////////////////////////////////////////////////////////////////////
}
